package com.renshine.base.service;

import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.renshine.base.bean.Assemble;
import com.renshine.base.bean.Field;
import com.renshine.base.bean.Item;
import com.renshine.base.bean.Table;
import com.renshine.base.dao.QueryDao;
import com.renshine.base.util.FileUtil;
import com.renshine.base.util.StringUtil;
import com.renshine.base.util.TemplateUtil;
import com.renshine.swing.model.EditTableModel;
import com.renshine.swing.model.ListTableModel;
import com.renshine.swing.model.SearchTableModel;

import freemarker.template.Configuration;
import freemarker.template.Template;

@Service
public class QueryServiceImpl implements QueryService{
	
	@Autowired
	QueryDao dao;

	@Override
	public String[] queryTbNames() {
		List<Table> tables = dao.queryTables();
		List<String> list = new ArrayList<String>();
		for (Table tb : tables) {
			list.add(tb.getName());
		}
		return list.toArray(new String[]{});
	}

	@Override
	public List<Object[]> tableRowDatas(String[] tbNames) {
		List<Table> tables = dao.queryTables();
		List<Object[]> list = new ArrayList<Object[]>();
		for (Table tb : tables) {
			List<Object> objs = new ArrayList<Object>();
			for (String tbName : tbNames) {
				if (!tbName.equals(tb.getName())) continue;
				objs.add(tb.getName());
				objs.add(tb.getComment());
				objs.add(StringUtil.convertToJavaEntity(tb.getName()));
				list.add(objs.toArray());
			}
		}
		return list;
	}

	@Override
	public String[] queryFdNames(String tbName) {
		List<Field> fields = dao.queryFields(tbName);
		List<String> list = new ArrayList<String>();
		for (Field field : fields) {
			list.add(field.getName());
		}
		return list.toArray(new String[]{});
	}

	@Override
	public List<Object[]> fieldEditRowDatas(String tbName, String[] fdNames) {
		List<Object[]> list = new ArrayList<Object[]>();
		List<Field> fields = dao.queryFields(tbName);
		for (Field field : fields) {
			List<Object> rowData =  new ArrayList<Object>();
			for (String fdName : fdNames) {
				if (!fdName.equals(field.getName())) continue;
				rowData.add(field.getName());
				rowData.add(field.getType());
				rowData.add(field.getComment());
				rowData.add(EditTableModel.VALIDATOR_TYPES[0]);
				list.add(rowData.toArray());
			}
		}
		return list;
	}

	@Override
	public List<Object[]> fieldSearcjRowDatas(String tbName, String[] fdNames) {
		List<Object[]> list = new ArrayList<Object[]>();
		List<Field> fields = dao.queryFields(tbName);
		for (Field field : fields) {
			List<Object> rowData =  new ArrayList<Object>();
			for (String fdName : fdNames) {
				if (!fdName.equals(field.getName())) continue;
				rowData.add(field.getName());
				rowData.add(field.getType());
				rowData.add(field.getComment());
				rowData.add(SearchTableModel.SEARCH_TYPES[0]);
				list.add(rowData.toArray());
			}
		}
		return list;
	}

	@Override
	public List<Object[]> fieldListRowDatas(String tbName, String[] fdNames) {
		List<Object[]> list = new ArrayList<Object[]>();
		List<Field> fields = dao.queryFields(tbName);
		for (Field field : fields) {
			if (field.isPri()) continue;// 剔除主键
			List<Object> rowData =  new ArrayList<Object>();
			for (String fdName : fdNames) {
				if (!fdName.equals(field.getName())) continue;
				rowData.add(field.getName());
				rowData.add(field.getType());
				rowData.add(field.getComment());
				rowData.add(ListTableModel.WIDTH_PERCENTAGE[0]);
				list.add(rowData.toArray());
			}
		}
		return list;
	}

	@Override
	public void createCode(Assemble assemble) {
		List<Item> items = assemble.getItems();
		String author;
		String Entity;
		String entity;
		String template;
		String codepath;
		String module;
		for (Item item : items) {
			author = assemble.getAuthor();
			Entity = item.getTb().getEntity();
			entity = StringUtil.firstCharLower(Entity);
			template = assemble.getTemplate();
			codepath = assemble.getCodepath();
			module = assemble.getModule();
			combItem(item); // 整理
			writeToTemplate(author, module, Entity, entity, template, codepath, item); // 写入模板
		}
	}

	private void combItem(Item item) {
		List<Field> fds = dao.queryFields(item.getTb().getName());
		// 属性初始化
		for (Field fd : fds) {fd.comb();}
		// 表整理
		item.getTb().setFds(fds);
		// 编辑字段的整理
		item.setListEdit(combItemList(item.getListEdit(), fds));
		item.setListSearch(combItemList(item.getListSearch(), fds));
		item.setListPage(combItemList(item.getListPage(), fds));
	}

	private List<Field> combItemList(List<Field> part, List<Field> all) {
		List<Field> newFds = new ArrayList<Field>();
		for (Field fdp : part) {
			if (fdp.isPri()) continue;// 剔除主键
			for (Field fda : all) {
				if (!fdp.getName().equals(fda.getName())) continue;
				// 复制拷贝
				BeanUtils.copyProperties(fda, fdp, new String[]{"condition"});
				newFds.add(fdp);
			}
		}
		return newFds;
	}

	/**
	 * 生成代码
	 * 
	 * @param author 作者
	 * @param module 模板名称
	 * @param Entity 类名称
	 * @param entity 实例名称
	 * @param template 模板名称
	 * @param codepath 生成路径
	 * @param item 配置的元素
	 */
	private void writeToTemplate(String author, String module, String Entity, String entity, String template, String codepath, Item item) {
		
		// 1.取得模板的路径
		List<String> templatePaths = TemplateUtil.getTemplatePaths(template);

		// 2.取得数据
		Map<String, Object> templateData = TemplateUtil.getDataMap(author, module, Entity, entity, item);

		// 3.模板 + 数据模型 ＝ 输出
		if (templatePaths != null && !templatePaths.isEmpty()) {
			Template tpt;
			String targetPath;
			try {
				Configuration cfg = new Configuration();
				cfg.setDefaultEncoding("utf-8");  
				cfg.setDirectoryForTemplateLoading(new File(FileUtil.getTemplateDirectory(template)));
				
				for (String templatePath : templatePaths) {
					tpt = cfg.getTemplate(templatePath);
					targetPath = TemplateUtil.getTargetPath(module, Entity, entity, templatePath, codepath);
					tpt.process(templateData, new FileWriter(targetPath));
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

}
